package com.xdf.ecommerce.filter;

import com.xdf.ecommerce.constant.CommonConstant;
import com.xdf.ecommerce.utils.TokenUtils;
import com.xdf.ecommerce.vo.LoginUserInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 1. 进入业务服务之前从 token 解析出用户信息，并填充到线程全局变量 ThreadLocal<LoginUserInfo> 中
 * 2. 请求结束后清理线程 ThreadLocal 的数据，防止内存泄露
 * 3. 特定的请求不需要拦截
 * @author chanchaw
 * @create 2025-10-24 16:55
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class LoginUserInfoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(isWhiteListUrl(request.getRequestURI())) return true;// 白名单URI不需要认证用户身份

        String token = request.getHeader(CommonConstant.JWT_USER_INFO_KEY);
        LoginUserInfo loginUserInfo = null;
        try{
            loginUserInfo = TokenUtils.getUserInfo(token);
        }catch (Exception ex) {
            log.error("将token转换为 LoginUserInfo 时出现异常：[{}]", ex.getMessage(),ex);
        }

        // 如果程序走到这里，说明 header 中没有 token，无法解析到用户信息
        // 没有通过系统认证，不可访问受限的API
        // 在网关中已经针对 token 做了校验了，实际不会走到这里
        // - 没有通过网关的认证，不会进入到本逻辑中
        if( null == loginUserInfo ) throw new RuntimeException("访问被禁止，没有登录或无法解析用户身份！");

        AccessContext.setLoginUserInfo(loginUserInfo);
        log.info("已将从token解析到的用户信息 [{}] 写入线程全局变量ThreadLocal<LoginUserInfo>",loginUserInfo);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 请求结束后的回调函数，一般在其中清理资源
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
        if(AccessContext.getLoginUserInfo() != null) AccessContext.clearLoginUserInfo();
    }

    // 白名单URL，不需要认证用户身份
    private boolean isWhiteListUrl(String url){
        boolean b = StringUtils.containsAny(url, "springfox", "swagger", "v2", "webjars", "doc.html", "swagger-ui.html","error");
        //log.info("检测 [{}] 属于白名单：[{}]", url, b);
        return b;
    }
}
